package com.aloda.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.aloda.annotation.RateLimit;
import com.aloda.cache.RedisUtils;
import com.aloda.constant.AppConstant;
import com.aloda.constant.ErrorCode;
import com.aloda.constant.ExceptionConstant;
import com.aloda.entity.App;
import com.aloda.entity.AppBrowse;
import com.aloda.enums.ReviewStatusEnum;
import com.aloda.exception.BaseException;
import com.aloda.exception.WarnException;
import com.aloda.mapper.AppBrowseMapper;
import com.aloda.mapper.AppMapper;
import com.aloda.query.AppBrowsePageDTO;
import com.aloda.result.PageResult;
import com.aloda.service.AppBrowseService;
import com.aloda.vo.app.AppBrowseCountVO;
import com.aloda.vo.app.AppBrowseExportVO;
import com.aloda.vo.app.AppBrowseVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class AppBrowseServiceImpl extends ServiceImpl<AppBrowseMapper, AppBrowse> implements AppBrowseService {

    @Resource
    private AppMapper appMapper;

    @Resource
    private AppBrowseMapper appBrowseMapper;

    @Resource
    private RedisUtils redisUtils;

    /**
     * 客户端获取app浏览排行榜
     *
     * @return
     */
    @Override
    public List<AppBrowseVO> getAppBrowseTop() {
        Set<String> topList = redisUtils
                .getAppBrowseTop(AppConstant.APP_BROWSE_TOP_NUM[0], AppConstant.APP_BROWSE_TOP_NUM[1]);
        if (topList == null || topList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> ids = topList.stream().map(Long::parseLong).toList();
        // 这里需要根据id进行排序，查询五个先用for循环
        ArrayList<App> appList = new ArrayList<>();
        for (Long id : ids) {
            App app = appMapper.selectById(id);
            appList.add(app);
        }
        return appList.stream().filter(app -> app.getReviewStatus().equals(ReviewStatusEnum.PASS.getValue()))
                .map(app -> BeanUtil.copyProperties(app, AppBrowseVO.class))
                .toList();
    }

    /**
     * 客户端增加app浏览量
     *
     * @param id
     * @return
     */
    @Override
    @RateLimit(period = 1)
    public Boolean addAppBrowse(Long id) {
        if (id == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        Double score = redisUtils.addAppBrowse(id);
        return score != null;
    }

    /**
     * 分页查询
     *
     * @param appBrowsePageDTO
     * @return
     */
    @Override
    public PageResult<AppBrowseCountVO> pageQuery(AppBrowsePageDTO appBrowsePageDTO) {
        Page<AppBrowse> page = appBrowsePageDTO.toMpPageDefaultSortByCreateTimeDesc();
        LambdaQueryWrapper<AppBrowse> appBrowseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appBrowseLambdaQueryWrapper.like(appBrowsePageDTO.getAppId() != null,
                        AppBrowse::getAppId, appBrowsePageDTO.getAppId())
                .like(appBrowsePageDTO.getAppName() != null,
                        AppBrowse::getAppName, appBrowsePageDTO.getAppName())
                .between(appBrowsePageDTO.getBeginTime() != null && appBrowsePageDTO.getEndTime() != null,
                        AppBrowse::getCreateTime, appBrowsePageDTO.getBeginTime(), appBrowsePageDTO.getEndTime());
        appBrowseMapper.selectPage(page, appBrowseLambdaQueryWrapper);
        return PageResult.of(page, AppBrowseCountVO.class);
    }

    @Override
    public List<AppBrowseCountVO> getTodayHotApp() {
        return BeanUtil.copyToList(getAllAppBrowse(), AppBrowseCountVO.class);
    }

    @Override
    public List<AppBrowse> getAllAppBrowse() {
        Set<String> idStringList = redisUtils.getTodayAllAppBrowse();
        if (idStringList == null || idStringList.isEmpty()) {
            return Collections.emptyList();
        }
        ArrayList<AppBrowse> appBrowses = new ArrayList<>();
        for (String id : idStringList) {
            AppBrowse appBrowse = new AppBrowse();
            Double score = redisUtils.getScoreById(id);
            if (score == null) {
                continue;
            }
            App app = appMapper.selectById(Long.valueOf(id));
            appBrowse.setAppId(Long.valueOf(id));
            appBrowse.setBrowseCount(score.longValue());
            appBrowse.setAppName(app.getAppName());
            appBrowse.setCreateTime(LocalDateTime.now());
            appBrowse.setUpdateTime(LocalDateTime.now());
            appBrowses.add(appBrowse);
        }
        return appBrowses;
    }

    /**
     * 删除指定id的应用今日浏览记录
     *
     * @param id
     * @return
     */
    @Override
    public Boolean deleteAppBrowseById(Long id) {
        return redisUtils.deleteAppBrowseById(id) > 0;
    }

    /**
     * 导出应用浏览量表格信息
     *
     * @param ids
     * @param response
     */
    @Override
    public void exportAppBrowseToExcel(List<Long> ids, HttpServletResponse response) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("应用浏览量信息表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 查询所有信息 如果ids为空查询所有信息，否则查询对应信息
            LambdaQueryWrapper<AppBrowse> queryWrapper = new LambdaQueryWrapper<>();
            List<AppBrowse> appBrowseList;
            if (ids.isEmpty()) {
                appBrowseList = appBrowseMapper.selectList(queryWrapper);
            } else {
                appBrowseList = appBrowseMapper.selectBatchIds(ids);
            }

            // 转换为导出VO
            List<AppBrowseExportVO> exportVOList = appBrowseList.stream().map(appBrowse -> {
                        AppBrowseExportVO appBrowseExportVO = BeanUtil.copyProperties(appBrowse, AppBrowseExportVO.class);
                        appBrowseExportVO.setId(appBrowse.getId().toString());
                        appBrowseExportVO.setAppId(appBrowse.getAppId().toString());
                        return appBrowseExportVO;
                    })
                    .collect(Collectors.toList());

            // 使用EasyExcel导出
            EasyExcel.write(response.getOutputStream(), AppBrowseExportVO.class)
                    .sheet("应用浏览量信息")
                    .doWrite(exportVOList);

        } catch (IOException e) {
            throw new RuntimeException(ExceptionConstant.EXPORT_EXCEL_ERROR, e);
        }
    }
}
